﻿using System.Threading;
using Audit.Core;
using Audit.WebApi;
using K9Nano.Domain;
using K9Nano.Remoting;
using K9Nano.Runtime;
using K9Nano.Share.Exceptions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using ISystemClock = K9Nano.Runtime.ISystemClock;

namespace K9Nano.AspNetCore.Audit
{
    public abstract class WebApiAuditDataProvider : AuditDataProvider
    {
        public IHttpContextAccessor HttpContextAccessor { get; }

        protected WebApiAuditDataProvider(IHttpContextAccessor httpContextAccessor)
        {
            HttpContextAccessor = httpContextAccessor;
        }
        
        protected CancellationToken CancellationToken => HttpContextAccessor.HttpContext?.RequestAborted ?? default;

        protected virtual AuditLog MapToLog(AuditEvent auditEvent)
        {
            if (auditEvent is AuditEventWebApi apiEvent)
            {
                var session = HttpContextAccessor.HttpContext.RequestServices.GetRequiredService<ISessionContext>();
                var systemClock = HttpContextAccessor.HttpContext.RequestServices.GetService<ISystemClock>();
                var apiInfo = HttpContextAccessor.HttpContext.RequestServices.GetService<IApiInfo>();
                var log = new AuditLog
                {
                    TenantId = session.TenantId,
                    UserId = session.UserId?.ToString(),
                    UserFullName = session.UserFullName,
                    Event = auditEvent.EventType,
                    Data = auditEvent.ToJson(),
                    AuditTime = systemClock.UtcNow,
                    EventId = apiEvent.Action.TraceId,
                    ApiName =  apiInfo.Name,
                    Status = apiEvent.Action.ResponseStatusCode,
                    Url = apiEvent.Action.RequestUrl
                };

                return log;
            }
            throw new K9Exception("WebApiAuditDataProvider should only be used to store AuditEventWebApi.");
        }

        protected virtual T MapToEvent<T>(AuditLog auditLog)
        {
            return System.Text.Json.JsonSerializer.Deserialize<T>(auditLog.Data);
        }
    }
}